/* Simple HTTP Server Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/

#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <esp_log.h>
#include <nvs_flash.h>
#include <sys/param.h>
#include "esp_netif.h"
#include "protocol_examples_common.h"
#include <esp_http_server.h>
#include "esp_event.h"
#include "esp_tls.h"
#include "esp_check.h"
#include <time.h>
#include <sys/time.h>
#if !CONFIG_IDF_TARGET_LINUX
#include <esp_wifi.h>
#include <esp_system.h>
#include "nvs_flash.h"
#endif  // !CONFIG_IDF_TARGET_LINUX

// 添加PWM和PCNT相关头文件
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/pulse_cnt.h"
#include "driver/gpio.h"
#include "driver/gptimer.h"
#include "driver/ledc.h"
//#include "driver/adc.h"
#include "esp_adc/adc_continuous.h"

#define HTTP_QUERY_KEY_MAX_LEN  (64)

/* A simple example that demonstrates how to create GET and POST
 * handlers for the web server.
 */

// 添加PCNT相关定义和变量
#define WIFISENSE_PCNT_HIGH_LIMIT 30000
#define WIFISENSE_PCNT_LOW_LIMIT  -30000

#define WIFISENSE_PULSE_GPIO 3
#define WIFISENSE_PWM_GPIO 2
#define WIFISENSE_PWM_FREQUENCY 240000 // 240kHz
#define WIFISENSE_PWM_DUTY_CYCLE 50 // 50%

// 添加新的PWM定义
#define WIFISENSE_PWM2_GPIO 4
#define WIFISENSE_PWM2_FREQUENCY 20000 // 20kHz
#define WIFISENSE_PWM2_DUTY_CYCLE 50 // 50%

// 检查GPIO是否可以用于PWM输出
#if WIFISENSE_PWM2_GPIO == 9 || WIFISENSE_PWM2_GPIO == 10
#warning "GPIO 9 and 10 are usually used for internal flash connection and may not work properly as PWM outputs"
#endif

// ADC相关定义
#define EXAMPLE_ADC_UNIT                 ADC_UNIT_1
#define EXAMPLE_ADC_CONV_MODE            ADC_CONV_SINGLE_UNIT_1
#define EXAMPLE_ADC_ATTEN                ADC_ATTEN_DB_12
#define EXAMPLE_ADC_BIT_WIDTH            SOC_ADC_DIGI_MAX_BITWIDTH
#define EXAMPLE_READ_LEN                 256

#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
#define EXAMPLE_ADC_OUTPUT_TYPE             ADC_DIGI_OUTPUT_FORMAT_TYPE1
#define EXAMPLE_ADC_GET_CHANNEL(p_data)     ((p_data)->type1.channel)
#define EXAMPLE_ADC_GET_DATA(p_data)        ((p_data)->type1.data)
#else
#define EXAMPLE_ADC_OUTPUT_TYPE             ADC_DIGI_OUTPUT_FORMAT_TYPE2
#define EXAMPLE_ADC_GET_CHANNEL(p_data)     ((p_data)->type2.channel)
#define EXAMPLE_ADC_GET_DATA(p_data)        ((p_data)->type2.data)
#endif

#define _EXAMPLE_ADC_UNIT_STR(unit)         #unit
#define EXAMPLE_ADC_UNIT_STR(unit)          _EXAMPLE_ADC_UNIT_STR(unit)

static adc_channel_t channel[4] = {ADC_CHANNEL_4, ADC_CHANNEL_5, ADC_CHANNEL_6, ADC_CHANNEL_7}; // GPIO5, GPIO6, GPIO7, GPIO8

static TaskHandle_t s_task_handle;
static adc_continuous_handle_t adc_handle = NULL;

// 将测量周期设置为10ms，以支持10Hz更新频率
#define MEASUREMENT_INTERVAL_MS 10

static const char *TAG = "wifi_sensor";
static pcnt_unit_handle_t g_pcnt_unit;
static int g_adc_values[4] = {0}; // 存储ADC值

// 用于存储测量结果的结构体
typedef struct {
    int pulse_count;
    int frequency;
} measurement_result_t;

static QueueHandle_t result_queue = NULL;
static int g_frequency = 0; // 存储当前频率值

// GPTimer callback for reading pulse count every 10ms
// 中断处理函数中只做最基本的操作，避免影响其他中断
static bool read_timer_callback(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
{
    BaseType_t high_task_wakeup = pdFALSE;
    if (g_pcnt_unit && result_queue) {
        measurement_result_t result = {0};
        // 只读取计数值，其他计算在任务中进行
        pcnt_unit_get_count(g_pcnt_unit, &result.pulse_count);
        
        // 发送结果到队列
        xQueueSendFromISR(result_queue, &result, &high_task_wakeup);
        
        // 清除计数器以便下次测量
        pcnt_unit_clear_count(g_pcnt_unit);
    }
    return high_task_wakeup == pdTRUE;
}

// 后台任务用于处理频率计算
static void frequency_update_task(void *arg)
{
    measurement_result_t result;
    pcnt_unit_handle_t pcnt_unit = (pcnt_unit_handle_t)arg;
    
    while (1) {
        // 从队列接收测量结果并在任务上下文中进行计算
        if (xQueueReceive(result_queue, &result, pdMS_TO_TICKS(20))) {
            // 在任务中进行频率计算，减轻中断处理负担
            // 频率(Hz) = 脉冲数 / 时间(s) = 脉冲数 / 0.01 = 脉冲数 * 100
            result.frequency = result.pulse_count * 100;
            g_frequency = result.frequency;
            // 移除日志打印，减少串口输出
        } else {
            // 如果队列为空，尝试直接读取
            int pulse_count = 0;
            pcnt_unit_get_count(pcnt_unit, &pulse_count);
            int frequency = pulse_count * 100;  // 10ms -> *100 得到Hz
            g_frequency = frequency;
            // 移除日志打印，减少串口输出
        }
    }
}

// 初始化PWM输出和PCNT输入
static void init_pwm_pcnt(void)
{
    result_queue = xQueueCreate(10, sizeof(measurement_result_t));
    if (!result_queue) {
        ESP_LOGE(TAG, "Failed to create queue");
        return;
    }

    // Configure PWM output on GPIO3 with 240kHz frequency and 50% duty cycle first
    ESP_LOGI(TAG, "configure PWM output on GPIO%d", WIFISENSE_PWM_GPIO);
    ledc_timer_config_t ledc_timer = {
        .speed_mode       = LEDC_LOW_SPEED_MODE,
        .timer_num        = LEDC_TIMER_0,
        .duty_resolution  = LEDC_TIMER_6_BIT, // 降低分辨率到6位以支持更高频率
        .freq_hz          = WIFISENSE_PWM_FREQUENCY,
        .clk_cfg          = LEDC_AUTO_CLK
    };
    ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));

    ledc_channel_config_t ledc_channel = {
        .gpio_num       = WIFISENSE_PWM_GPIO,
        .speed_mode     = LEDC_LOW_SPEED_MODE,
        .channel        = LEDC_CHANNEL_0,
        .intr_type      = LEDC_INTR_DISABLE,
        .timer_sel      = LEDC_TIMER_0,
        .duty           = (64 * WIFISENSE_PWM_DUTY_CYCLE) / 100, // 64是6位分辨率的最大值+1
        .hpoint         = 0
    };
    ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
    
    // 添加新的PWM通道配置 (GPIO4, 20kHz)
    ESP_LOGI(TAG, "configure second PWM output on GPIO%d", WIFISENSE_PWM2_GPIO);
    ledc_timer_config_t ledc_timer2 = {
        .speed_mode       = LEDC_LOW_SPEED_MODE,
        .timer_num        = LEDC_TIMER_1,
        .duty_resolution  = LEDC_TIMER_10_BIT, // 10位分辨率
        .freq_hz          = WIFISENSE_PWM2_FREQUENCY,
        .clk_cfg          = LEDC_AUTO_CLK
    };
    ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer2));

    ledc_channel_config_t ledc_channel2 = {
        .gpio_num       = WIFISENSE_PWM2_GPIO,
        .speed_mode     = LEDC_LOW_SPEED_MODE,
        .channel        = LEDC_CHANNEL_1,
        .intr_type      = LEDC_INTR_DISABLE,
        .timer_sel      = LEDC_TIMER_1,
        .duty           = (1024 * WIFISENSE_PWM2_DUTY_CYCLE) / 100, // 1024是10位分辨率的最大值+1
        .hpoint         = 0
    };
    ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel2));
    
    // 更新PWM通道以启动输出
    ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0));
    ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1));
    
    ESP_LOGI(TAG, "PWM output configured: GPIO%d, %d Hz, %d%% duty cycle", 
             WIFISENSE_PWM_GPIO, WIFISENSE_PWM_FREQUENCY, WIFISENSE_PWM_DUTY_CYCLE);
             
    ESP_LOGI(TAG, "Second PWM output configured: GPIO%d, %d Hz, %d%% duty cycle", 
             WIFISENSE_PWM2_GPIO, WIFISENSE_PWM2_FREQUENCY, WIFISENSE_PWM2_DUTY_CYCLE);

    ESP_LOGI(TAG, "install pcnt unit");
    pcnt_unit_config_t unit_config = {
        .high_limit = WIFISENSE_PCNT_HIGH_LIMIT,
        .low_limit = WIFISENSE_PCNT_LOW_LIMIT,
    };
    pcnt_unit_handle_t pcnt_unit = NULL;
    ESP_ERROR_CHECK(pcnt_new_unit(&unit_config, &pcnt_unit));
    g_pcnt_unit = pcnt_unit;

    ESP_LOGI(TAG, "set glitch filter");
    pcnt_glitch_filter_config_t filter_config = {
        .max_glitch_ns = 10,
    };
    ESP_ERROR_CHECK(pcnt_unit_set_glitch_filter(pcnt_unit, &filter_config));

    ESP_LOGI(TAG, "install pcnt channel");
    pcnt_chan_config_t chan_config = {
        .edge_gpio_num = WIFISENSE_PULSE_GPIO,
        .level_gpio_num = -1, // Not used
    };
    pcnt_channel_handle_t pcnt_chan = NULL;
    ESP_ERROR_CHECK(pcnt_new_channel(pcnt_unit, &chan_config, &pcnt_chan));

    ESP_LOGI(TAG, "set edge and level actions for pcnt channel");
    // 只计数上升沿，这样更符合预期
    ESP_ERROR_CHECK(pcnt_channel_set_edge_action(pcnt_chan, PCNT_CHANNEL_EDGE_ACTION_INCREASE, PCNT_CHANNEL_EDGE_ACTION_HOLD));
    ESP_ERROR_CHECK(pcnt_channel_set_level_action(pcnt_chan, PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_KEEP));

    ESP_LOGI(TAG, "enable pcnt unit");
    ESP_ERROR_CHECK(pcnt_unit_enable(pcnt_unit));
    ESP_LOGI(TAG, "clear pcnt unit");
    ESP_ERROR_CHECK(pcnt_unit_clear_count(pcnt_unit));
    ESP_LOGI(TAG, "start pcnt unit");
    ESP_ERROR_CHECK(pcnt_unit_start(pcnt_unit));

    // Configure and start GPTimer for reading count every 10ms
    gptimer_handle_t gptimer_read_handle;
    gptimer_config_t read_timer_config = {
        .clk_src = GPTIMER_CLK_SRC_DEFAULT,
        .direction = GPTIMER_COUNT_UP,
        .resolution_hz = 1000000, // 1MHz resolution
    };
    ESP_ERROR_CHECK(gptimer_new_timer(&read_timer_config, &gptimer_read_handle));
    
    gptimer_alarm_config_t read_alarm_config = {
        .alarm_count = MEASUREMENT_INTERVAL_MS * 1000, // 50ms at 1MHz
        .reload_count = 0,
        .flags.auto_reload_on_alarm = true,
    };
    gptimer_event_callbacks_t read_cbs = {
        .on_alarm = read_timer_callback,
    };
    ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer_read_handle, &read_cbs, NULL));
    ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer_read_handle, &read_alarm_config));
    ESP_ERROR_CHECK(gptimer_enable(gptimer_read_handle));
    ESP_ERROR_CHECK(gptimer_start(gptimer_read_handle));
    
    // 创建后台任务用于更新频率
    xTaskCreate(frequency_update_task, "frequency_update_task", 2048, (void *)pcnt_unit, 5, NULL);
}

// 设置PWM频率的函数
static esp_err_t set_pwm_frequency(int frequency)
{
    // 根据项目规范，限制频率在120kHz到550kHz范围内
    if (frequency < 120000 || frequency > 550000) {
        return ESP_ERR_INVALID_ARG;
    }
    
    // 更新PWM频率
    ESP_ERROR_CHECK(ledc_set_freq(LEDC_LOW_SPEED_MODE, LEDC_TIMER_0, frequency));
    ESP_LOGI(TAG, "PWM frequency updated to %d Hz", frequency);
    return ESP_OK;
}

// 添加设置第二个PWM占空比的函数
static esp_err_t set_pwm2_duty_cycle(int duty_cycle)
{
    // 限制占空比在0-100之间
    if (duty_cycle < 0 || duty_cycle > 100) {
        return ESP_ERR_INVALID_ARG;
    }
    
    // 计算10位分辨率下的实际duty值
    uint32_t duty = (1024 * duty_cycle) / 100;
    
    // 更新PWM占空比
    ESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, duty));
    ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1));
    ESP_LOGI(TAG, "Second PWM duty cycle updated to %d%%", duty_cycle);
    return ESP_OK;
}

/* An HTTP GET handler */
static esp_err_t root_get_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "text/html; charset=utf-8");
    
    char *resp_str = "<!DOCTYPE html>"
                     "<html>"
                     "<head>"
                     "<meta charset='utf-8'>"
                     "<meta name='viewport' content='width=device-width, initial-scale=1'>"
                     "<link rel='icon' type='image/x-icon' href='/favicon.ico'>"
                     "<title>WiFi传感器频率检测与控制</title>"
                     "<style>body{font-family:Arial,Helvetica,sans-serif;margin:12px}.chart{width:100%;max-width:900px;height:300px;border:1px solid #ccc;margin:8px 0}#toolbar{margin:8px 0}button,input{margin-right:6px}.legend{font-size:12px;margin:4px 0}.legend span{display:inline-block;margin-right:10px}.swatch{display:inline-block;width:10px;height:10px;margin-right:4px;vertical-align:middle}</style>"
                     "<script>"
                     "(function(){"
                     "  var key='freq_history';"
                     "  var maxPoints=1200;"  /* 约2分钟@10Hz */
                     "  var pollMs=100;"     /* 100ms 拉取一次，实现10Hz更新 */
                     "  var useSession=true;"  /* 可切换为Memory: false */
                     "  var data=[], labels=[];"  /* 频率曲线数据 */
                     "  var adcData=[[],[],[],[]]; var adcLabels=[];" /* ADC四通道数据 */
                     "  var lastTs=0;"
                     "  function loadCache(){"
                     "    try{var raw=(useSession?sessionStorage:window)._getItem?null:null}catch(e){}"
                     "    try{var raw=(useSession?sessionStorage:localStorage).getItem(key); if(raw){var obj=JSON.parse(raw); data=obj.data||[]; labels=obj.labels||[];}}catch(e){}"
                     "  }"
                     "  function saveCache(){"
                     "    try{(useSession?sessionStorage:localStorage).setItem(key, JSON.stringify({data:data,labels:labels}));}catch(e){}"
                     "  }"
                     "  function clearCache(){ data=[]; labels=[]; adcData=[[],[],[],[]]; adcLabels=[]; saveCache(); redraw(); redrawAdc(); }"
                     "  function nowLabel(){var d=new Date();return [d.getHours(),d.getMinutes(),d.getSeconds()].map(function(x){return (x<10?'0':'')+x}).join(':');}"
                     "  function pushPoint(val){"
                     "    data.push(val); labels.push(nowLabel());"
                     "    if(data.length>maxPoints){data.shift(); labels.shift();}"
                     "  }"
                     "  var canvas,ctx, adcCanvas,adcCtx;"
                     "  function initCanvas(){"
                     "    canvas=document.getElementById('chart'); ctx=canvas.getContext('2d');"
                     "    adcCanvas=document.getElementById('adcChart'); adcCtx=adcCanvas.getContext('2d');"
                     "    resizeCanvas(); window.addEventListener('resize', resizeCanvas);"
                     "  }"
                     "  function resizeCanvas(){var w1=canvas.clientWidth||600; var h1=canvas.clientHeight||300; canvas.width=w1; canvas.height=h1; var w2=adcCanvas.clientWidth||600; var h2=adcCanvas.clientHeight||300; adcCanvas.width=w2; adcCanvas.height=h2; redraw(); redrawAdc();}"
                     "  function drawAxes(ctx,width,height,mm){ctx.save(); ctx.strokeStyle='#999'; ctx.lineWidth=1; ctx.beginPath(); ctx.moveTo(40,10); ctx.lineTo(40,height-25); ctx.lineTo(width-10,height-25); ctx.stroke(); ctx.fillStyle='#666'; ctx.font='12px Arial'; if(mm){ctx.fillText('max:'+mm.max, 45, 20); ctx.fillText('min:'+mm.min, 45, height-30);} for(var i=0;i<=4;i++){var y=10+i*((height-35)/4); ctx.strokeStyle='#e0e0e0'; ctx.beginPath(); ctx.moveTo(40,y); ctx.lineTo(width-10,y); ctx.stroke();} ctx.restore();}"
                     "  function getMinMax(arr){if(arr.length===0){return {min:0,max:1}} var mn=arr[0], mx=arr[0]; for(var i=1;i<arr.length;i++){var v=arr[i]; if(v<mn) mn=v; if(v>mx) mx=v;} if(mn===mx){mn=mn-1; mx=mx+1;} return {min:mn,max:mx};}"
                     "  function redraw(){ if(!ctx) return; ctx.clearRect(0,0,canvas.width,canvas.height); var plotW=canvas.width, plotH=canvas.height; var mm=getMinMax(data); drawAxes(ctx,plotW,plotH,mm); var range=mm.max-mm.min; if(data.length<2) return; ctx.save(); ctx.strokeStyle='#1976d2'; ctx.lineWidth=2; ctx.beginPath(); for(var i=0;i<data.length;i++){var x=40 + i*((plotW-50)/(data.length-1)); var y=(10)+( (mm.max-data[i])/range )*(plotH-35); if(i===0) ctx.moveTo(x,y); else ctx.lineTo(x,y);} ctx.stroke(); ctx.restore(); }"
                     "  var colors=['#e53935','#43a047','#fb8c00','#8e24aa'];"
                     "  function redrawAdc(){ if(!adcCtx) return; var w=adcCanvas.width, h=adcCanvas.height; adcCtx.clearRect(0,0,w,h); var merged=[]; for(var c=0;c<4;c++){merged=merged.concat(adcData[c]);} var mm=getMinMax(merged.length?merged:[0,1]); drawAxes(adcCtx,w,h,mm); var range=mm.max-mm.min; adcCtx.save(); adcCtx.lineWidth=1.8; for(var c=0;c<4;c++){var arr=adcData[c]; if(arr.length<2) continue; adcCtx.strokeStyle=colors[c]; adcCtx.beginPath(); for(var i=0;i<arr.length;i++){var x=40 + i*((w-50)/(arr.length-1)); var y=(10)+( (mm.max-arr[i])/range )*(h-35); if(i===0) adcCtx.moveTo(x,y); else adcCtx.lineTo(x,y);} adcCtx.stroke(); } adcCtx.restore(); }"
                     "  function updateFrequency(){"
                     "    fetch('/freq_val').then(function(r){return r.text()}).then(function(t){"
                     "      var v=parseInt(t)||0; document.getElementById('freq').innerText=v+' Hz';"
                     "      pushPoint(v); saveCache(); redraw();"
                     "    }).catch(function(){ /* 网络异常时不报错打断 */ });"
                     "  }"
                     "  function updateAdcValues(){"
                     "    fetch('/adc_val').then(function(response){return response.json();}).then(function(data){"
                     "      document.getElementById('adc0').innerText = 'ADC0 (GPIO5): ' + data.adc0;"
                     "      document.getElementById('adc1').innerText = 'ADC1 (GPIO6): ' + data.adc1;"
                     "      document.getElementById('adc2').innerText = 'ADC2 (GPIO7): ' + data.adc2;"
                     "      document.getElementById('adc3').innerText = 'ADC3 (GPIO8): ' + data.adc3;"
                       "      var label=nowLabel(); adcLabels.push(label); if(adcLabels.length>maxPoints){adcLabels.shift();}"
                       "      var vals=[data.adc0|0,data.adc1|0,data.adc2|0,data.adc3|0];"
                       "      for(var c=0;c<4;c++){adcData[c].push(vals[c]); if(adcData[c].length>maxPoints){adcData[c].shift();}}"
                       "      redrawAdc();"
                     "    }).catch(function(){ /* 网络异常时不报错打断 */ });"
                     "  }"
                     "  function start(){ loadCache(); initCanvas(); redraw(); redrawAdc(); setInterval(updateFrequency, pollMs); setInterval(updateAdcValues, 200); }"
                     "  window.clearHistory=function(){ clearCache(); };"
                     "  window.switchStorage=function(){ useSession=!useSession; loadCache(); saveCache(); redraw(); document.getElementById('storageMode').innerText=useSession?'SessionStorage':'Local Memory'; };"
                     "  window.addEventListener('load', start);"
                     "})();"
                     "function setFrequency() {"
                     "  var freq = document.getElementById('freq_input').value;"
                     "  fetch('/set_freq?freq=' + freq)"
                     "    .then(function(response){"
                     "      if (response.ok) {"
                     "        document.getElementById('status').innerText = '频率设置成功';"
                     "      } else {"
                     "        document.getElementById('status').innerText = '频率设置失败';"
                     "      }"
                     "    });"
                     "}"
                     "function setPwm2Duty() {"
                     "  var duty = document.getElementById('pwm2_duty_input').value;"
                     "  fetch('/set_pwm2_duty?duty=' + duty)"
                     "    .then(function(response){"
                     "      if (response.ok) {"
                     "        document.getElementById('pwm2_status').innerText = '占空比设置成功';"
                     "      } else {"
                     "        document.getElementById('pwm2_status').innerText = '占空比设置失败';"
                     "      }"
                     "    });"
                     "}"
                     "</script>"
                     "</head>"
                     "<body>"
                     "<h1>WiFi传感器频率检测与控制</h1>"
                     "<p>当前检测频率: <span id='freq'>%d</span></p>"
                     "<div id='toolbar'>"
                     "  <button onclick='clearHistory()'>清空历史</button>"
                     "  <button onclick='switchStorage()'>切换缓存介质</button>"
                     "  <span>当前缓存: <b id='storageMode'>SessionStorage</b></span>"
                     "</div>"
                     "<div>"
                     "  <p id='adc0'>ADC0 (GPIO5): --</p>"
                     "  <p id='adc1'>ADC1 (GPIO6): --</p>"
                     "  <p id='adc2'>ADC2 (GPIO7): --</p>"
                     "  <p id='adc3'>ADC3 (GPIO8): --</p>"
                     "</div>"
                     "<div class='legend'><span><span class='swatch' style='background:#1976d2'></span>频率(Hz)</span></div>"
                     "<canvas id='chart' class='chart'></canvas>"
                     "<div class='legend'>"
                     "  <span><span class='swatch' style='background:#e53935'></span>ADC0 (GPIO5)</span>"
                     "  <span><span class='swatch' style='background:#43a047'></span>ADC1 (GPIO6)</span>"
                     "  <span><span class='swatch' style='background:#fb8c00'></span>ADC2 (GPIO7)</span>"
                     "  <span><span class='swatch' style='background:#8e24aa'></span>ADC3 (GPIO8)</span>"
                     "</div>"
                     "<canvas id='adcChart' class='chart'></canvas>"
                     "<h2>频率控制</h2>"
                     "<p>"
                     "  <label for='freq_input'>设置传感器输出频率 (120000-550000 Hz): </label><br>"
                     "  <input type='number' id='freq_input' min='120000' max='550000' value='%d'>"
                     "  <button onclick='setFrequency()'>设置频率</button>"
                     "</p>"
                     "<p id='status'></p>"
                     "<h2>第二路PWM控制</h2>"
                     "<p>"
                     "  <label for='pwm2_duty_input'>设置第二路PWM占空比 (0-100%%): </label><br>"
                     "  <input type='number' id='pwm2_duty_input' min='0' max='100' value='50'>"
                     "  <button onclick='setPwm2Duty()'>设置占空比</button>"
                     "</p>"
                     "<p id='pwm2_status'></p>"
                     "<h2>接口说明</h2>"
                     "<p>本系统提供以下REST API接口：</p>"
                    "<ul>"
                    "<li><code>GET /freq_val</code> - 获取当前检测到的传感器频率值（Hz）</li>"
                    "<li><code>GET /adc_val</code> - 获取ADC通道原始采样值（0-4095），返回JSON：adc0..adc3</li>"
                    "<li><code>GET /set_freq?freq=&lt;频率值&gt;</code> - 设置传感器输出频率，频率范围：120000 Hz 到 550000 Hz</li>"
                    "<li><code>GET /set_pwm2_duty?duty=&lt;占空比&gt;</code> - 设置第二路PWM占空比，范围：0-100%</li>"
                    "</ul>"
                     "</body>"
                     "</html>";
    
    // 计算响应的最大可能长度（HTML模板长度 + 频率数字长度）
    size_t resp_len = strlen(resp_str) + 20 + 20; // 两个数字的最大长度
    
    char *resp_buffer = malloc(resp_len);
    if (resp_buffer == NULL) {
        ESP_LOGE(TAG, "Failed to allocate memory for HTTP response");
        httpd_resp_send_500(req);
        return ESP_FAIL;
    }
    
    snprintf(resp_buffer, resp_len, resp_str, g_frequency, WIFISENSE_PWM_FREQUENCY);
    httpd_resp_send(req, resp_buffer, HTTPD_RESP_USE_STRLEN);
    free(resp_buffer);
    return ESP_OK;
}

static const httpd_uri_t root = {
    .uri       = "/",
    .method    = HTTP_GET,
    .handler   = root_get_handler,
    .user_ctx  = NULL
};
// 添加一个新的处理函数用于获取ADC值
static esp_err_t adc_val_get_handler(httpd_req_t *req)
{
    ESP_LOGI(TAG, "ADC value requested");
    
    // 设置CORS头，允许所有来源访问
    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
    httpd_resp_set_hdr(req, "Access-Control-Allow-Methods", "GET");
    httpd_resp_set_hdr(req, "Access-Control-Allow-Headers", "Content-Type");
    
    // 设置缓存控制头，防止浏览器缓存结果
    httpd_resp_set_hdr(req, "Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
    httpd_resp_set_hdr(req, "Pragma", "no-cache");
    
    // 设置响应类型为JSON
    httpd_resp_set_type(req, "application/json");
    
    char adc_response[200];
    snprintf(adc_response, sizeof(adc_response),
             "{\"adc0\": %d, \"adc1\": %d, \"adc2\": %d, \"adc3\": %d}",
             g_adc_values[0], g_adc_values[1], g_adc_values[2], g_adc_values[3]);
    
    ESP_LOGI(TAG, "Sending ADC values: %s", adc_response);
    
    // 发送响应
    esp_err_t err = httpd_resp_send(req, adc_response, HTTPD_RESP_USE_STRLEN);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Error sending ADC response: %d", err);
        return err;
    }
    
    return ESP_OK;
}
// ADC URI处理
static const httpd_uri_t adc_val = {
    .uri       = "/adc_val",
    .method    = HTTP_GET,
    .handler   = adc_val_get_handler,
    .user_ctx  = NULL
};
static esp_err_t freq_val_get_handler(httpd_req_t *req)
{
    char *freq_str = malloc(20);
    if (freq_str == NULL) {
        ESP_LOGE(TAG, "Failed to allocate memory for frequency value");
        httpd_resp_send_500(req);
        return ESP_FAIL;
    }
    
    snprintf(freq_str, 20, "%d", g_frequency);
    httpd_resp_send(req, freq_str, HTTPD_RESP_USE_STRLEN);
    free(freq_str);
    return ESP_OK;
}

static const httpd_uri_t freq_val = {
    .uri       = "/freq_val",
    .method    = HTTP_GET,
    .handler   = freq_val_get_handler,
    .user_ctx  = NULL
};

// 新增的设置频率的处理函数
static esp_err_t set_freq_get_handler(httpd_req_t *req)
{
    char *buf = NULL;
    size_t buf_len;
    
    // 获取URL查询参数
    buf_len = httpd_req_get_url_query_len(req) + 1;
    if (buf_len > 1) {
        buf = malloc(buf_len);
        if (buf == NULL) {
            ESP_LOGE(TAG, "Failed to allocate memory for query string");
            httpd_resp_send_500(req);
            return ESP_FAIL;
        }
        
        if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
            char freq_str[12] = {0};
            if (httpd_query_key_value(buf, "freq", freq_str, sizeof(freq_str)) == ESP_OK) {
                int freq = atoi(freq_str);
                if (set_pwm_frequency(freq) == ESP_OK) {
                    httpd_resp_send(req, "OK", 2);
                    free(buf);
                    return ESP_OK;
                } else {
                    httpd_resp_send(req, "ERROR: Invalid frequency", 23);
                    free(buf);
                    return ESP_FAIL;
                }
            }
        }
        free(buf);
    }
    
    httpd_resp_send(req, "ERROR: Missing frequency parameter", 33);
    return ESP_FAIL;
}

static const httpd_uri_t set_freq = {
    .uri       = "/set_freq",
    .method    = HTTP_GET,
    .handler   = set_freq_get_handler,
    .user_ctx  = NULL
};

// 新增的设置第二路PWM占空比的处理函数
static esp_err_t set_pwm2_duty_get_handler(httpd_req_t *req)
{
    char *buf = NULL;
    size_t buf_len;
    
    // 获取URL查询参数
    buf_len = httpd_req_get_url_query_len(req) + 1;
    if (buf_len > 1) {
        buf = malloc(buf_len);
        if (buf == NULL) {
            ESP_LOGE(TAG, "Failed to allocate memory for query string");
            httpd_resp_send_500(req);
            return ESP_FAIL;
        }
        
        if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
            char duty_str[12] = {0};
            if (httpd_query_key_value(buf, "duty", duty_str, sizeof(duty_str)) == ESP_OK) {
                int duty = atoi(duty_str);
                if (set_pwm2_duty_cycle(duty) == ESP_OK) {
                    httpd_resp_send(req, "OK", 2);
                    free(buf);
                    return ESP_OK;
                } else {
                    httpd_resp_send(req, "ERROR: Invalid duty cycle", 28);
                    free(buf);
                    return ESP_FAIL;
                }
            }
        }
        free(buf);
    }
    
    httpd_resp_send(req, "ERROR: Missing duty parameter", 31);
    return ESP_FAIL;
}

static const httpd_uri_t set_pwm2_duty = {
    .uri       = "/set_pwm2_duty",
    .method    = HTTP_GET,
    .handler   = set_pwm2_duty_get_handler,
    .user_ctx  = NULL
};

// Favicon handler
extern const uint8_t favicon_ico_start[] asm("_binary_favicon_ico_start");
extern const uint8_t favicon_ico_end[]   asm("_binary_favicon_ico_end");

static esp_err_t favicon_get_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "image/x-icon");
    httpd_resp_send(req, (const char *)favicon_ico_start, favicon_ico_end - favicon_ico_start);
    return ESP_OK;
}

static const httpd_uri_t favicon = {
    .uri       = "/favicon.ico",
    .method    = HTTP_GET,
    .handler   = favicon_get_handler,
    .user_ctx  = NULL
};

/* An HTTP GET handler */
static esp_err_t hello_get_handler(httpd_req_t *req)
{
    char*  buf;
    size_t buf_len;

    /* Get header value string length and allocate memory for length + 1,
     * extra byte for null termination */
    buf_len = httpd_req_get_hdr_value_len(req, "Host") + 1;
    if (buf_len > 1) {
        buf = malloc(buf_len);
        ESP_RETURN_ON_FALSE(buf, ESP_ERR_NO_MEM, TAG, "buffer alloc failed");
        /* Copy null terminated value string into buffer */
        if (httpd_req_get_hdr_value_str(req, "Host", buf, buf_len) == ESP_OK) {
            ESP_LOGI(TAG, "Found header => Host: %s", buf);
        }
        free(buf);
    }

    buf_len = httpd_req_get_hdr_value_len(req, "Test-Header-2") + 1;
    if (buf_len > 1) {
        buf = malloc(buf_len);
        ESP_RETURN_ON_FALSE(buf, ESP_ERR_NO_MEM, TAG, "buffer alloc failed");
        if (httpd_req_get_hdr_value_str(req, "Test-Header-2", buf, buf_len) == ESP_OK) {
            ESP_LOGI(TAG, "Found header => Test-Header-2: %s", buf);
        }
        free(buf);
    }

    buf_len = httpd_req_get_hdr_value_len(req, "Test-Header-1") + 1;
    if (buf_len > 1) {
        buf = malloc(buf_len);
        ESP_RETURN_ON_FALSE(buf, ESP_ERR_NO_MEM, TAG, "buffer alloc failed");
        if (httpd_req_get_hdr_value_str(req, "Test-Header-1", buf, buf_len) == ESP_OK) {
            ESP_LOGI(TAG, "Found header => Test-Header-1: %s", buf);
        }
        free(buf);
    }

    /* Read URL query string length and allocate memory for length + 1,
     * extra byte for null termination */
    buf_len = httpd_req_get_url_query_len(req) + 1;
    if (buf_len > 1) {
        buf = malloc(buf_len);
        ESP_RETURN_ON_FALSE(buf, ESP_ERR_NO_MEM, TAG, "buffer alloc failed");
        if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
            ESP_LOGI(TAG, "Found URL query => %s", buf);
            char param[HTTP_QUERY_KEY_MAX_LEN], dec_param[HTTP_QUERY_KEY_MAX_LEN] = {0};
            /* Get value of expected key from query string */
            if (httpd_query_key_value(buf, "query1", param, sizeof(param)) == ESP_OK) {
                ESP_LOGI(TAG, "Found URL query parameter => query1=%s", param);
                // example_uri_decode(dec_param, param, strnlen(param, HTTP_QUERY_KEY_MAX_LEN));
                ESP_LOGI(TAG, "Decoded query parameter => %s", dec_param);
            }
            if (httpd_query_key_value(buf, "query3", param, sizeof(param)) == ESP_OK) {
                ESP_LOGI(TAG, "Found URL query parameter => query3=%s", param);
                // example_uri_decode(dec_param, param, strnlen(param, HTTP_QUERY_KEY_MAX_LEN));
                ESP_LOGI(TAG, "Decoded query parameter => %s", dec_param);
            }
            if (httpd_query_key_value(buf, "query2", param, sizeof(param)) == ESP_OK) {
                ESP_LOGI(TAG, "Found URL query parameter => query2=%s", param);
                // example_uri_decode(dec_param, param, strnlen(param, HTTP_QUERY_KEY_MAX_LEN));
                ESP_LOGI(TAG, "Decoded query parameter => %s", dec_param);
            }
        }
        free(buf);
    }

    /* Set some custom headers */
    httpd_resp_set_hdr(req, "Custom-Header-1", "Custom-Value-1");
    httpd_resp_set_hdr(req, "Custom-Header-2", "Custom-Value-2");

    /* Send response with custom headers and body set as the
     * string passed in user context*/
    const char* resp_str = (const char*) req->user_ctx;
    httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);

    /* After sending the HTTP response the old HTTP request
     * headers are lost. Check if HTTP request headers can be read now. */
    if (httpd_req_get_hdr_value_len(req, "Host") == 0) {
        ESP_LOGI(TAG, "Request headers lost");
    }
    return ESP_OK;
}

static const httpd_uri_t hello = {
    .uri       = "/hello",
    .method    = HTTP_GET,
    .handler   = hello_get_handler,
    /* Let's pass response string in user
     * context to demonstrate it's usage */
    .user_ctx  = "Hello World!"
};

/* An HTTP POST handler */
static esp_err_t echo_post_handler(httpd_req_t *req)
{
    char buf[100];
    int ret, remaining = req->content_len;

    while (remaining > 0) {
        /* Read the data for the request */
        if ((ret = httpd_req_recv(req, buf,
                        MIN(remaining, sizeof(buf)))) <= 0) {
            if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
                /* Retry receiving if timeout occurred */
                continue;
            }
            return ESP_FAIL;
        }

        /* Send back the same data */
        httpd_resp_send_chunk(req, buf, ret);
        remaining -= ret;

        /* Log data received */
        ESP_LOGI(TAG, "=========== RECEIVED DATA ==========");
        ESP_LOGI(TAG, "%.*s", ret, buf);
        ESP_LOGI(TAG, "====================================");
    }

    // End response
    httpd_resp_send_chunk(req, NULL, 0);
    return ESP_OK;
}

static const httpd_uri_t echo = {
    .uri       = "/echo",
    .method    = HTTP_POST,
    .handler   = echo_post_handler,
    .user_ctx  = NULL
};

/* An HTTP_ANY handler */
static esp_err_t any_handler(httpd_req_t *req)
{
    /* Send response with body set as the
     * string passed in user context*/
    const char* resp_str = (const char*) req->user_ctx;
    httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);

    // End response
    httpd_resp_send_chunk(req, NULL, 0);
    return ESP_OK;
}

static const httpd_uri_t any = {
    .uri       = "/any",
    .method    = HTTP_ANY,
    .handler   = any_handler,
    /* Let's pass response string in user
     * context to demonstrate it's usage */
    .user_ctx  = "Hello World!"
};

/* This handler allows the custom error handling functionality to be
 * tested from client side. For that, when a PUT request 0 is sent to
 * URI /ctrl, the /hello and /echo URIs are unregistered and following
 * custom error handler http_404_error_handler() is registered.
 * Afterwards, when /hello or /echo is requested, this custom error
 * handler is invoked which, after sending an error message to client,
 * either closes the underlying socket (when requested URI is /echo)
 * or keeps it open (when requested URI is /hello). This allows the
 * client to infer if the custom error handler is functioning as expected
 * by observing the socket state.
 */
esp_err_t http_404_error_handler(httpd_req_t *req, httpd_err_code_t err)
{
    if (strcmp("/hello", req->uri) == 0) {
        httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "/hello URI is not available");
        /* Return ESP_OK to keep underlying socket open */
        return ESP_OK;
    } else if (strcmp("/echo", req->uri) == 0) {
        httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "/echo URI is not available");
        /* Return ESP_FAIL to close underlying socket */
        return ESP_FAIL;
    }
    /* For any other URI send 404 and close socket */
    httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "Some 404 error message");
    return ESP_FAIL;
}

/* An HTTP PUT handler. This demonstrates realtime
 * registration and deregistration of URI handlers
 */
static esp_err_t ctrl_put_handler(httpd_req_t *req)
{
    char buf;
    int ret;

    if ((ret = httpd_req_recv(req, &buf, 1)) <= 0) {
        if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
            httpd_resp_send_408(req);
        }
        return ESP_FAIL;
    }

    if (buf == '0') {
        /* URI handlers can be unregistered using the uri string */
        ESP_LOGI(TAG, "Unregistering /hello and /echo URIs");
        httpd_unregister_uri(req->handle, "/hello");
        httpd_unregister_uri(req->handle, "/echo");
        /* Register the custom error handler */
        httpd_register_err_handler(req->handle, HTTPD_404_NOT_FOUND, http_404_error_handler);
    }
    else {
        ESP_LOGI(TAG, "Registering /hello and /echo URIs");
        httpd_register_uri_handler(req->handle, &hello);
        httpd_register_uri_handler(req->handle, &echo);
        /* Unregister custom error handler */
        httpd_register_err_handler(req->handle, HTTPD_404_NOT_FOUND, NULL);
    }

    /* Respond with empty body */
    httpd_resp_send(req, NULL, 0);
    return ESP_OK;
}

static const httpd_uri_t ctrl = {
    .uri       = "/ctrl",
    .method    = HTTP_PUT,
    .handler   = ctrl_put_handler,
    .user_ctx  = NULL
};



static httpd_handle_t start_webserver(void)
{
    httpd_handle_t server = NULL;
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();
    // 增加可注册的URI数量，默认仅为8，当前项目已超过
    config.max_uri_handlers = 16;
#if CONFIG_IDF_TARGET_LINUX
    // Setting port as 8001 when building for Linux. Port 80 can be used only by a privileged user in linux.
    // So when a unprivileged user tries to run the application, it throws bind error and the server is not started.
    // Port 8001 can be used by an unprivileged user as well. So the application will not throw bind error and the
    // server will be started.
    config.server_port = 8001;
#endif // !CONFIG_IDF_TARGET_LINUX
    config.lru_purge_enable = true;

    // Start the httpd server
    ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
    if (httpd_start(&server, &config) == ESP_OK) {
        // Set URI handlers
        ESP_LOGI(TAG, "Registering URI handlers");
        httpd_register_uri_handler(server, &hello);
        httpd_register_uri_handler(server, &echo);
        httpd_register_uri_handler(server, &ctrl);
        httpd_register_uri_handler(server, &any);
        httpd_register_uri_handler(server, &root);       // 注册根路径页面
        httpd_register_uri_handler(server, &freq_val);   // 注册频率值接口
        httpd_register_uri_handler(server, &set_freq);   // 注册设置频率接口
        httpd_register_uri_handler(server, &set_pwm2_duty); // 注册设置第二路PWM占空比接口
        httpd_register_uri_handler(server, &favicon);    // 注册favicon图标接口
        httpd_register_uri_handler(server, &adc_val);    // 注册ADC值接口
        ESP_LOGI(TAG, "ADC URI handler registered: %s", adc_val.uri);
#if CONFIG_EXAMPLE_ENABLE_SSE_HANDLER
        httpd_register_uri_handler(server, &sse); // Register SSE handler
#endif

        return server;
    }

    ESP_LOGI(TAG, "Error starting server!");
    return NULL;
}

#if !CONFIG_IDF_TARGET_LINUX
static esp_err_t stop_webserver(httpd_handle_t server)
{
    // Stop the httpd server
    return httpd_stop(server);
}

static void disconnect_handler(void* arg, esp_event_base_t event_base,
                               int32_t event_id, void* event_data)
{
    httpd_handle_t* server = (httpd_handle_t*) arg;
    if (*server) {
        ESP_LOGI(TAG, "Stopping webserver");
        if (stop_webserver(*server) == ESP_OK) {
            *server = NULL;
        } else {
            ESP_LOGE(TAG, "Failed to stop http server");
        }
    }
}

static void connect_handler(void* arg, esp_event_base_t event_base,
                            int32_t event_id, void* event_data)
{
    httpd_handle_t* server = (httpd_handle_t*) arg;
    if (*server == NULL) {
        ESP_LOGI(TAG, "Starting webserver");
        *server = start_webserver();
    }
}
#endif // !CONFIG_IDF_TARGET_LINUX

// ADC连续读取回调函数
static bool IRAM_ATTR s_conv_done_cb(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *user_data)
{
    BaseType_t mustYield = pdFALSE;
    //Notify that ADC continuous driver has done enough number of conversions
    vTaskNotifyGiveFromISR(s_task_handle, &mustYield);

    return (mustYield == pdTRUE);
}

// 初始化ADC连续读取模式
static void continuous_adc_init(adc_channel_t *channel, uint8_t channel_num, adc_continuous_handle_t *out_handle)
{
    adc_continuous_handle_t handle = NULL;

    adc_continuous_handle_cfg_t adc_config = {
        .max_store_buf_size = 1024,
        .conv_frame_size = EXAMPLE_READ_LEN,
    };
    ESP_ERROR_CHECK(adc_continuous_new_handle(&adc_config, &handle));

    adc_continuous_config_t dig_cfg = {
        .sample_freq_hz = 20 * 1000,
        .conv_mode = EXAMPLE_ADC_CONV_MODE,
        .format = EXAMPLE_ADC_OUTPUT_TYPE,
    };

    adc_digi_pattern_config_t adc_pattern[SOC_ADC_PATT_LEN_MAX] = {0};
    dig_cfg.pattern_num = channel_num;
    for (int i = 0; i < channel_num; i++) {
        adc_pattern[i].atten = EXAMPLE_ADC_ATTEN;
        adc_pattern[i].channel = channel[i] & 0x7;
        adc_pattern[i].unit = EXAMPLE_ADC_UNIT;
        adc_pattern[i].bit_width = EXAMPLE_ADC_BIT_WIDTH;

        ESP_LOGI(TAG, "adc_pattern[%d].atten is :%"PRIx8, i, adc_pattern[i].atten);
        ESP_LOGI(TAG, "adc_pattern[%d].channel is :%"PRIx8, i, adc_pattern[i].channel);
        ESP_LOGI(TAG, "adc_pattern[%d].unit is :%"PRIx8, i, adc_pattern[i].unit);
    }
    dig_cfg.adc_pattern = adc_pattern;
    ESP_ERROR_CHECK(adc_continuous_config(handle, &dig_cfg));

    *out_handle = handle;
}

// ADC读取任务
static void adc_read_task(void *arg)
{
    esp_err_t ret;
    uint32_t ret_num = 0;
    uint8_t result[EXAMPLE_READ_LEN] = {0};
    memset(result, 0xcc, EXAMPLE_READ_LEN);
    
    s_task_handle = xTaskGetCurrentTaskHandle();
    
    // 注册回调函数
    adc_continuous_evt_cbs_t cbs = {
        .on_conv_done = s_conv_done_cb,
    };
    ESP_ERROR_CHECK(adc_continuous_register_event_callbacks(adc_handle, &cbs, NULL));
    ESP_ERROR_CHECK(adc_continuous_start(adc_handle));

    char unit[] = EXAMPLE_ADC_UNIT_STR(EXAMPLE_ADC_UNIT);
    
    ESP_LOGI(TAG, "ADC read task started");

    while (1) {
        // 等待转换完成通知
        ulTaskNotifyTake(pdTRUE, portMAX_DELAY);

        while (1) {
            ret = adc_continuous_read(adc_handle, result, EXAMPLE_READ_LEN, &ret_num, 0);
            if (ret == ESP_OK) {
                // 解析读取到的数据
                for (int i = 0; i < ret_num; i += SOC_ADC_DIGI_RESULT_BYTES) {
                    adc_digi_output_data_t *p = (adc_digi_output_data_t*)&result[i];
                    uint32_t chan_num = EXAMPLE_ADC_GET_CHANNEL(p);
                    uint32_t data = EXAMPLE_ADC_GET_DATA(p);
                    
                    // 检查通道号有效性并更新对应ADC值
                    if (chan_num < SOC_ADC_CHANNEL_NUM(EXAMPLE_ADC_UNIT)) {
                        // 直接根据通道号更新对应的ADC值
                        if (chan_num == 4) {
                            g_adc_values[0] = data;
                           // ESP_LOGI(TAG, "ADC unit: %s, channel: %d (GPIO5), value: %d", unit, chan_num, data);
                        } else if (chan_num == 5) {
                            g_adc_values[1] = data;
                           // ESP_LOGI(TAG, "ADC unit: %s, channel: %d (GPIO6), value: %d", unit, chan_num, data);
                        } else if (chan_num == 6) {
                            g_adc_values[2] = data;
                           // ESP_LOGI(TAG, "ADC unit: %s, channel: %d (GPIO7), value: %d", unit, chan_num, data);
                        } else if (chan_num == 7) {
                            g_adc_values[3] = data;
                           // ESP_LOGI(TAG, "ADC unit: %s, channel: %d (GPIO8), value: %d", unit, chan_num, data);
                        }
                    }
                }
                /**
                 * Because printing is slow, so every time you call `ulTaskNotifyTake`, it will immediately return.
                 * To avoid a task watchdog timeout, add a delay here. When you replace the way you process the data,
                 * usually you don't need this delay (as this task will block for a while).
                 */
                vTaskDelay(1);
            } else if (ret == ESP_ERR_TIMEOUT) {
                // 没有更多数据可读取
                break;
            }
        }
    }
    
    // 停止并释放ADC资源
    ESP_ERROR_CHECK(adc_continuous_stop(adc_handle));
    ESP_ERROR_CHECK(adc_continuous_deinit(adc_handle));
}

// 初始化ADC
static void init_adc(void)
{
    // 初始化连续ADC模式
    continuous_adc_init(channel, sizeof(channel) / sizeof(adc_channel_t), &adc_handle);

    // 创建任务定期读取ADC值
    xTaskCreate(adc_read_task, "adc_read_task", 4096, NULL, 5, NULL);
}





void app_main(void)
{
    static httpd_handle_t server = NULL;

    ESP_ERROR_CHECK(nvs_flash_init());
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
     * Read "Establishing Wi-Fi or Ethernet Connection" section in
     * examples/protocols/README.md for more information about this function.
     */
    ESP_ERROR_CHECK(example_connect());

    /* Register event handlers to stop the server when Wi-Fi or Ethernet is disconnected,
     * and re-start it upon connection.
     */
#if !CONFIG_IDF_TARGET_LINUX

#endif // !CONFIG_IDF_TARGET_LINUX

    /* Start the server for the first time */
    server = start_webserver();
    
    // 初始化PWM和PCNT功能
    init_pwm_pcnt();
    
    // 初始化ADC功能
    init_adc();

    ESP_LOGI(TAG, "ADC initialization completed");

    while (server) {
        sleep(5);
    }
}
